#pragma once

#include <vector>
#include <set>
#include <queue>
#include <string>
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/BasicBlock.h"
#include "llvm/Instruction.h"
#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Instructions.h"
#include "MemoryProfiler.h"
#include <sys/types.h>
#include <sys/mman.h>
#include "PrefetchInstr.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <map>

using namespace llvm;
using namespace std;

class Slicer
{
public:
	Slicer(Function *Src, Function *Dst, vector<Instruction*> &Splitters, ExecutionEngine *EE, ValueToValueMapTy &RevVMap);
	Instruction* Slice(set<Instruction*> &HotLoads);
private:
	Function *Src, *Dst;
	set<Instruction*> Vital;
	Module *M;
	ExecutionEngine *EE;
	LLVMContext &C;
	ValueToValueMapTy VMap;
	Callable Func;

	void FixTerminators(map<Value*, Value*> &Dependents);
	void CopyFunction(ValueToValueMapTy &RevVMap);
	void AddTerminators();
	void AddStores(set<Value*> &AvoidanceSet);
	void AddFunctionCalls(string Name);
	void Translate(vector<Instruction*> &In, vector<Instruction*> &Out);
	void Complement(set<Value*> &Slice, set<Instruction*> &ToBeRemoved);
	void Split(vector<Instruction*> &Splitters);
};
